/*
 * @Author: 武兴创 superjava@qq.com
 * @Date: 2024-08-14 15:58:41
 * @LastEditors: 武兴创 superjava@vip.qq.com
 * @LastEditTime: 2024-08-28 17:38:32
 * @FilePath: \SGFEM\DataStructure\Common\include\Validation.h
 * @Description:  用来对比与验证
 *
 */
#pragma once

#include <cmath>
#include <iostream>

#include <boost/test/tools/floating_point_comparison.hpp>

#include "DataStructure/Common/Constant.h"
template <class T>
bool is_close (T expect, T got, T tolerance)
{
    using boost::math::fpc::close_at_tolerance;
    using boost::math::fpc::FPC_STRONG;
    using boost::math::fpc::is_small;

    if (is_small<T> (expect, tolerance))
    {
        return is_small<T> (got, tolerance);
    }

    return close_at_tolerance<T> (tolerance, FPC_STRONG) (expect, got);
}

SG_DATASTRUCTURE_COMMON_NAMESPACE_OPEN
/**
 * @brief 判断两个浮点数是否接近
 *
 * 判断给定的两个浮点数 `a` 和 `b` 是否在指定的容差范围内接近。
 *
 * @param a 第一个浮点数
 * @param b 第二个浮点数
 *
 * @return 如果 `a` 和 `b` 的差的绝对值小于 `SG::DataStructure::Common::TOLERANCE`，则返回 `true`；否则返回 `false`
 */
inline bool isNear (Real a, Real b, Real tolerance = SG::DataStructure::Common::TOLERANCE)
{
    // 判断两个浮点数是否接近，即它们之间的差的绝对值是否小于某个设定的容忍度
    // return std::fabs (a - b) <= tolerance * std::min (std::fabs (a), std::fabs (b));
    return is_close (a, b, tolerance);
}

/// @brief 判断两个值是否相等
/// @tparam T 数据类型
/// @param val1
/// @param val2
/// @return
template <typename T>
inline bool isEQ (T val1, T val2)
{
    return val1 == val2;
}

/// @brief 对于Real类型使用容差来判断
/// @param val1
/// @param val2
/// @return
template <>
inline bool isEQ (Real val1, Real val2)
{
    return isNear (val1, val2);
}

SG_DATASTRUCTURE_COMMON_NAMESPACE_CLOSE

// 在结构体中在 重载== 时来使用。如果不等,返回false
// 两个要对比的变量需要名称为 val1 与 val2
#define FIELD_COMPARE(field)                                       \
    if (!SG::DataStructure::Common::isEQ (val1.field, val2.field)) \
    {                                                              \
        return false;                                              \
    }

// 同上 用来对比数组
#define FIELD_COMPARE_ARR(field, len)                                        \
    for (size_t i = 0; i < len; i++)                                         \
    {                                                                        \
        if (!SG::DataStructure::Common::isEQ (val1.field[i], val2.field[i])) \
        {                                                                    \
            return false;                                                    \
        }                                                                    \
    }
